package au.com.iglootech.TaxTimeToolTip.dao;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import javax.annotation.PostConstruct;
import javax.jdo.PersistenceManagerFactory;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.ObjectRetrievalFailureException;
import org.springframework.orm.jdo.JdoTemplate;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import au.com.iglootech.TaxTimeToolTip.Entity.IGTDomainEntity;
import au.com.iglootech.TaxTimeToolTip.Exception.AppX;

import com.google.appengine.api.datastore.Key;

@Repository(GenericDao.BEANNAME)
@Transactional(readOnly = false)
public class GenericDao {
	public static final String BEANNAME = "GenericDao";

	@Autowired
	private PersistenceManagerFactory pmf;

	private JdoTemplate jdoTemplate;

	@PostConstruct
	void createJdoTemplate() {
		jdoTemplate = new JdoTemplate(pmf);
	}

	@Transactional(readOnly = true)
	public <T extends IGTDomainEntity> T findByKey(Class<T> clazz, Key id) {
		@SuppressWarnings("unchecked")
		T entity = (T) jdoTemplate.detachCopy(jdoTemplate.getObjectById(clazz,
				id));

		if (entity == null) {
			throw new ObjectRetrievalFailureException(clazz, id);
		}
		return entity;
	}

	@Transactional(readOnly = true)
	@SuppressWarnings("unchecked")
	public <T extends IGTDomainEntity> Collection<T> findAll(Class<T> clazz) {
		return jdoTemplate.detachCopyAll(jdoTemplate.find(clazz));
	}

	@Transactional
	@SuppressWarnings("unchecked")
	public <T extends IGTDomainEntity> void remove(T domainObj) {
		T domainObject = (T) jdoTemplate.getObjectById(domainObj.getClass(),
				domainObj.getKey());
		jdoTemplate.deletePersistent(domainObject);
	}

	@Transactional(readOnly = true)
	@SuppressWarnings("unchecked")
	public <T extends IGTDomainEntity> Collection<T> findByNamedQuery(
			Class<T> clazz, String namedQuery, Map<String, Object> values) {
		return jdoTemplate.findByNamedQuery(clazz, namedQuery, values);
	}

	@Transactional(readOnly = true)
	@SuppressWarnings("unchecked")
	public <T extends IGTDomainEntity> Collection<T> findByKeys(Class<T> clazz,
			List<Key> keys) {
		List<T> entities = new ArrayList<T>();
			for (Key key : keys) {
				entities.add(findByKey(clazz, key));
			}
		return entities;
	}

	@Transactional
	@SuppressWarnings("unchecked")
	public <T extends Object> T save(T domainObj) {
		return (T) jdoTemplate.makePersistent(domainObj);
	}

	@Transactional
	public void flush() {
		jdoTemplate.flush();
	}

	@Transactional
	public <T extends IGTDomainEntity> void refresh(T domainObj) {
		jdoTemplate.refresh(domainObj);
	}

	public PersistenceManagerFactory getPmf() {
		return pmf;
	}

	public JdoTemplate getJdoTemplate() {
		return jdoTemplate;
	}

}
